package com.accounting.juanjuan.utils;

import com.accounting.juanjuan.constant.FileType;
import com.accounting.juanjuan.exception.BizException;
import org.springframework.lang.Nullable;
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Array;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 断言<br>
 * 断言某些对象或值是否符合规定，否则抛出异常。经常用于做变量检查
 */
public class Assert {
    /**
     * 检查文件是否为excel文件
     */
    public static void isExcelFile(MultipartFile multipartFile) {
        isNotNull(multipartFile, "文件");
        if (multipartFile.getSize() == 0) {
            throw new BizException("文件内容不能为空！");
        }
        String originalFilename = multipartFile.getOriginalFilename();
        isNotBlank(originalFilename, "文件名称");
        String extension = StringUtil.getExtension(originalFilename);
        isNotBlank(extension, "文件后缀名");
        if (!FileType.EXCEL_FILE_XLS.equals(extension) && !FileType.EXCEL_FILE_XLSx.equals(extension)) {
            throw new BizException("文件必须为excel文件！");
        }
    }

    /**
     * 判断字符串为空的断言
     *
     * @param str     字符串
     * @param strName 字符串的名称
     * @throws BizException 如果为空抛出BizException
     */
    public static void isNotBlank(@Nullable String str, String strName) throws BizException {
        isNotBlank(str, () -> new BizException("【" + strName + "】信息项不允许为空，请检查！"));
    }

    /**
     * 判断字符串为空的断言
     *
     * @param str           字符串
     * @param errorSupplier 异常Supplier
     * @param <X>           异常类型
     * @throws X 异常泛型
     */
    public static <X extends Throwable> void isNotBlank(@Nullable String str, @Nullable Supplier<X> errorSupplier) throws X {
        if (StringUtil.isBlank(str)) {
            throw errorSupplier.get();
        }
    }

    /**
     * 断言字符串，存在非空（非null,空串,空白串）字符
     *
     * @param text          字符串
     * @param errorSupplier 异常Supplier
     * @param <X>           异常类型
     * @throws X 异常泛型
     */
    public static <X extends Throwable> void hasText(@Nullable String text, @Nullable Supplier<X> errorSupplier) throws X {
        if (!StringUtil.hasText(text)) {
            throw errorSupplier.get();
        }
    }

    /**
     * 断言字符串，存在非空（非null,空串,空白串）字符
     *
     * @param text    字符串
     * @param message 错误信息
     * @throws IllegalArgumentException 不合法参数异常
     */
    public static void hasText(@Nullable String text, @Nullable String message) throws IllegalArgumentException {
        hasText(text, () -> new IllegalArgumentException(message));
    }

    /***
     * 用于断言字符串非空，如果非空则执行consumer函数
     * @param text 文本
     * @param consumer 非空的执行函数
     */
    public static void hasText(@Nullable String text, @Nullable Consumer<String> consumer) {
        if (StringUtil.hasText(text)) {
            consumer.accept(text);
        }
    }

    /**
     * 判断数据为空的断言
     *
     * @param obj  数据
     * @param name 数据名称
     * @throws BizException 如果为空抛出BizException
     */
    public static void isNotNull(@Nullable Object obj, String name) throws BizException {
        isNotNull(obj, () -> new BizException("【" + name + "】信息项不允许为空，请检查！"));
    }

    /**
     * 判断数据为空的断言
     *
     * @param obj           数据
     * @param errorSupplier 异常Supplier
     * @param <X>           异常类型
     * @throws X 异常泛型
     */
    public static <X extends Throwable> void isNotNull(@Nullable Object obj, @Nullable Supplier<X> errorSupplier) throws X {
        if (Objects.isNull(obj)) {
            throw errorSupplier.get();
        }
    }

    /**
     * 判断Map为空的断言
     *
     * @param map  数据
     * @param name 数据名称
     * @throws BizException 如果为null或不包含键值对抛出BizException
     */
    public static void isNotEmpty(@Nullable Map map, String name) throws BizException {
        isNotEmpty(map, () -> new BizException("【" + name + "】信息项不允许为空，请检查！"));
    }

    /**
     * 判断List为空的断言
     *
     * @param list 数据
     * @param name 数据名称
     * @throws BizException 如果为null或不包含任何元素抛出BizException
     */
    public static void isNotEmpty(@Nullable List list, String name) throws BizException {
        isNotEmpty(list, () -> new BizException("【" + name + "】信息项不允许为空，请检查！"));
    }

    /**
     * 判断Set为空的断言
     *
     * @param set  数据
     * @param name 数据名称
     * @throws BizException 如果为null或不包含任何元素抛出BizException
     */
    public static void isNotEmpty(@Nullable Set set, String name) throws BizException {
        isNotEmpty(set, () -> new BizException("【" + name + "】信息项不允许为空，请检查！"));
    }

    /**
     * 断言对象不为Empty
     * <p>
     * 为null或者不存在数据，则视为Empty，
     * 兼容多种数据类型（Optional，CharSequence，map,array,Collection等），自动识别。
     * </p>
     *
     * @param obj           对象
     * @param errorSupplier 异常Supplier
     * @param <X>           异常类型
     * @throws X 异常泛型
     */
    public static <X extends Throwable> void isNotEmpty(@Nullable Object obj, @Nullable Supplier<X> errorSupplier) throws X {
        if (Objects.isNull(obj)) {
            throw errorSupplier.get();
        }
        if (obj instanceof Optional && !((Optional) obj).isPresent()) {
            throw errorSupplier.get();
        }
        if (obj instanceof CharSequence && StringUtil.isEmpty((CharSequence) obj)) {
            throw errorSupplier.get();
        }
        if (obj.getClass().isArray() && Array.getLength(obj) == 0) {
            throw errorSupplier.get();
        }
        if (obj instanceof Collection && ((Collection<?>) obj).isEmpty()) {
            throw errorSupplier.get();
        }
        if (obj instanceof Map && ((Map<?, ?>) obj).isEmpty()) {
            throw errorSupplier.get();
        }
    }

    /**
     * 判断查询结果为空的断言
     *
     * @param list     查询结果
     * @param listName 数据名称
     * @throws BizException 如果为空抛出BizException
     */
    public static void isQueryNotEmpty(@Nullable List list, String listName) throws BizException {
        isNotEmpty(list, () -> new BizException("未查询到【" + listName + "】！"));
    }

    /**
     * 判断查询结果为空的断言
     *
     * @param map     查询结果
     * @param mapName 数据名称
     * @throws BizException 如果为空抛出BizException
     */
    public static void isQueryNotEmpty(@Nullable Map map, String mapName) throws BizException {
        isNotEmpty(map, () -> new BizException("未查询到【" + mapName + "】！"));
    }

    /**
     * 判断查询结果为空的断言
     *
     * @param optional     查询结果
     * @param optionalName 数据名称
     * @throws BizException 如果为空抛出BizException
     */
    public static void isQueryNotEmpty(@Nullable Optional optional, String optionalName) throws BizException {
        isNotEmpty(optional, () -> new BizException("未查询到【" + optionalName + "】！"));
    }

    /**
     * 判断查询结果为空的断言
     *
     * @param obj     查询结果
     * @param objName 数据名称
     * @throws BizException 如果为空抛出BizException
     */
    public static void isQueryNotNull(@Nullable Object obj, String objName) throws BizException {
        isNotNull(obj, () -> new BizException("未查询到【" + objName + "】！"));
    }

    /**
     * 断言expression=true
     *
     * @param expression 表达式
     * @param message    错误信息
     * @throws IllegalArgumentException 不合法参数异常
     */
    public static void isTrue(boolean expression, @Nullable String message) throws IllegalArgumentException {
        isTrue(expression, () -> new IllegalArgumentException(message));
    }


    /**
     * 断言expression=true
     *
     * @param expression    表达式
     * @param errorSupplier 异常Supplier
     * @param <X>           异常类型
     * @throws X 异常泛型
     */
    public static <X extends Throwable> void isTrue(boolean expression, @Nullable Supplier<X> errorSupplier) throws X {
        if (!expression) {
            throw errorSupplier.get();
        }
    }
}